home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / signals.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  6.9 KB  |  328 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/signals.c,v 2.1 90/10/04 18:26:46 melissa Exp $";
  10. #endif
  11.  
  12. /*
  13.  * Signal handling support for MM.
  14.  */
  15.  
  16. #include "mm.h"
  17.  
  18. #ifndef sigmask
  19. #define sigmask(m) (1 << ((m) - 1))
  20. #endif
  21.  
  22. #ifndef NSIG
  23. #define NSIG 32
  24. #endif
  25.  
  26. long signal_mask = 0, deferred_signals = 0;
  27. signalhandler signal_handler();
  28.  
  29. /*
  30.  * Set up signal handlers
  31.  */
  32.  
  33. int
  34. init_signals ()
  35. {
  36.     signal_mask = ~0;
  37.     deferred_signals = 0;
  38.  
  39.     (void) signal (SIGHUP, signal_handler);
  40.     (void) signal (SIGALRM, signal_handler);
  41.     (void) signal (SIGINT, signal_handler);
  42. #ifdef SIGPIPE
  43.     (void) signal (SIGPIPE, signal_handler);
  44. #endif
  45. #ifdef SIGTSTP
  46.     (void) signal (SIGTSTP, signal_handler);
  47. #endif
  48. #ifdef SIGXCPU
  49.     (void) signal (SIGXCPU, signal_handler);
  50. #endif
  51. #ifdef SIGCHLD
  52.     (void) signal (SIGCHLD, signal_handler);
  53. #endif
  54.     release_signals (0L);
  55. }
  56.  
  57. /*
  58.  * Block signals we want to lock out.  On BSD systems this
  59.  * just calls sigblock(); on others, we maintain our own signal mask:
  60.  * the signal_handler routine will catch signals and remember they
  61.  * happened, so their handlers can be invoked by release_signals.
  62.  */
  63.  
  64. long
  65. block_signals ()
  66. {
  67.     long m = signal_mask;
  68.     signal_mask |= sigmask (SIGHUP) | sigmask (SIGINT) |
  69. #ifdef SIGPIPE
  70.         sigmask (SIGPIPE) |
  71. #endif
  72. #ifdef SIGTSTP
  73.     sigmask (SIGTSTP) |
  74. #endif
  75. #ifdef SIGCONT
  76.     sigmask (SIGCONT) |
  77. #endif
  78. #ifdef SIGCHLD
  79.     sigmask (SIGCHLD) |
  80. #endif
  81. #ifdef SIGXCPU
  82.     sigmask (SIGXCPU) |
  83. #endif
  84.     sigmask (SIGALRM);
  85. #ifdef HAVE_BSD_SIGNALS
  86.     return sigblock (signal_mask);
  87. #else
  88.     return m;
  89. #endif
  90. }
  91.  
  92. /*
  93.  * Restore the signal mask, and invoke handlers for any pending signals
  94.  */
  95. release_signals (m)
  96. long m;
  97. {
  98. #ifdef HAVE_BSD_SIGNALS
  99.     (void) sigsetmask (m);
  100. #endif
  101.     signal_mask = m;
  102.     if (deferred_signals)
  103.     run_deferred_signals ();
  104. }
  105.  
  106. queue_signal (sig)
  107. int sig;
  108. {
  109.     deferred_signals |= sigmask (sig);
  110. }
  111.  
  112. run_deferred_signals ()
  113. {
  114.     int i;
  115.     long m = deferred_signals & ~signal_mask;
  116.  
  117.     for (i = 0; (i < NSIG) && m; i++)
  118.     if (m & sigmask (i)) {
  119.         m &= ~sigmask(i);
  120.         handle_signal (i);
  121.     }
  122. }
  123.  
  124. /*
  125.  * This routine is the only one we install as a signal handler using
  126.  * signal(2).  On BSD systems it just calls handle_signal(), while on
  127.  * other systems it may defer invocation of the handler if the signal
  128.  * has been disabled with block_signals.
  129.  */
  130.  
  131. signalhandler
  132. signal_handler (sig)
  133. int sig;
  134. {
  135. #ifdef HAVE_BSD_SIGNALS
  136.     handle_signal (sig);
  137. #else
  138.     unsigned long b = sigmask (sig);
  139.  
  140.     if (signal_mask & b) {
  141.     queue_signal (sig);
  142.     if (sig != SIGCHLD)
  143.         signal (sig, signal_handler);
  144.     return;
  145.     }
  146.  
  147.     handle_signal (sig);
  148.     signal (sig, signal_handler);
  149. #endif
  150.     return;
  151. }
  152.  
  153. /*
  154.  * Dispatch to handle signal SIG.
  155.  */
  156.  
  157. handle_signal (sig)
  158. int sig;
  159. {
  160.     deferred_signals &= ~sigmask (sig);
  161.  
  162.     switch (sig) {
  163.       case SIGALRM:
  164.     new_mail (true);
  165.     break;
  166.       case SIGINT:
  167.     sigint_handler ();
  168.     break;
  169.       case SIGHUP:
  170.     sighup_handler ();
  171.     break;
  172. #ifdef SIGPIPE
  173.       case SIGPIPE:            /* ignore */
  174.     break;
  175. #endif
  176. #ifdef SIGCHLD
  177.       case SIGCHLD:
  178.     collect_process (0);
  179.     break;
  180. #endif
  181. #ifdef SIGXCPU
  182.       case SIGXCPU:
  183.     sigxcpu_handler ();
  184.     break;
  185. #endif
  186. #ifdef SIGTSTP
  187.       case SIGTSTP:
  188.     write (1, "\r\n", 2);        /* move to new line */
  189.     suspend (0);            /* suspend ourself */
  190.     break;
  191. #endif
  192.     }
  193. }
  194.  
  195. /*
  196.  * This routine should be called before and after any synchronous fork/wait
  197.  * sequences; arg should be "true" on the first call and "false" on the
  198.  * second.
  199.  *
  200.  * This routine serves to disable the SIGCHLD handler for callers who want
  201.  * to wait for children to exit, and saves/restores the tty process group
  202.  * for ill-behaved children who may change the tty process group and not
  203.  * change it back before suspending themselves or exiting (e.g. ksh).
  204.  *
  205.  */
  206.  
  207. fix_signals_for_fork (before_the_fork)
  208. int before_the_fork;
  209. {
  210. #ifdef SIGCHLD
  211.     static signalhandler (*old_chld_handler)() = 0;
  212. #endif
  213.     signalhandler (*tmp)() = 0;
  214.     static int ttypgrp = -1, nesting = 0;
  215.     if (before_the_fork) {
  216.     if (nesting++ != 0)
  217.         return;
  218. #ifdef TIOCGPGRP
  219.     if (isatty(2)) {
  220.         tmp = signal (SIGTTIN, SIG_IGN);
  221.         (void) ioctl (0, TIOCGPGRP, &ttypgrp);
  222.         if (tmp != SIG_IGN)
  223.         signal (SIGTTIN, tmp);
  224.     }
  225. #endif
  226. #ifdef SIGCHLD
  227.     old_chld_handler = signal (SIGCHLD, SIG_DFL);
  228. #endif
  229.     }
  230.     else {
  231. #ifdef TIOCGPGRP
  232.     if (--nesting != 0)
  233.         return;
  234.     if (isatty(2) && ttypgrp > 0) {
  235.         tmp = signal (SIGTTOU, SIG_IGN);
  236.         (void) ioctl (2, TIOCSPGRP, &ttypgrp);
  237.         if (tmp != SIG_IGN)
  238.         signal (SIGTTOU, tmp);
  239.     }
  240.     ttypgrp = -1;
  241. #endif
  242. #ifdef SIGCHLD
  243.     (void) signal (SIGCHLD, old_chld_handler);
  244. #endif
  245.     }
  246. }
  247.  
  248. /*
  249.  * SIGINT and SIGQUIT must be ignored around blocking wait calls.
  250.  * SIGTSTP should use the default signal handler.
  251.  */
  252.  
  253. fix_signals_for_wait (before_the_wait)
  254. int before_the_wait;
  255. {
  256.     static nesting = 0;
  257.     static signalhandler (*old_handlers[3]) ();
  258.     
  259.     if (before_the_wait) {
  260.     if (++nesting == 1) {
  261.         old_handlers[0] = signal (SIGINT, SIG_IGN);
  262.         old_handlers[1] = signal (SIGQUIT, SIG_IGN);
  263. #ifdef SIGTSTP
  264.         old_handlers[2] = signal (SIGTSTP, SIG_DFL);
  265. #endif
  266.     }
  267.     }
  268.     else {
  269.     if (--nesting == 0) {
  270.         (void) signal (SIGINT, old_handlers[0]);
  271.         (void) signal (SIGQUIT, old_handlers[1]);
  272. #ifdef SIGTSTP
  273.         (void) signal (SIGTSTP, old_handlers[2]);
  274. #endif
  275.     }
  276.     }
  277. }
  278.  
  279. /*
  280.  * mm_popen and mm_pclose:
  281.  
  282.  * Since MM traps SIGCHLD (to catch whatever sendmails it sent into
  283.  * the background), it will wait() on the pipe process.  In fact, when
  284.  * any process finishes, the SIGCHLD handler catches it.  So, when
  285.  * pclose() does a wait, it never gets any processes.  The wait (in
  286.  * pclose()) cannot return until all processes have sent their
  287.  * SIGCHLDs and been waited on by the SIGCHLD handler.  This means
  288.  * that pclose() must wait() until all those really SLOW sendmail
  289.  * processes are done, which is pretty slow.
  290.  * 
  291.  * Therefore, in order to guarantee that the pipe process is still
  292.  * around for pclose() to wait() on, we block or ignore all SIGCHLD
  293.  * signals before we do the popen(), and turn our SIGCHLD handler back
  294.  * on after the pclose() is done.  (Note that this may allow pclose()
  295.  * to catch some of our sendmail processes, if they end before the
  296.  * pipe process, but we check for that in maybe_wait_for_process().
  297.  */
  298.  
  299. static signalhandler (*old_handler)();
  300.  
  301. FILE *
  302. mm_popen (command, type)
  303. char *command, *type;
  304. {
  305.     FILE *stream;
  306.  
  307. #ifdef SIGCHLD
  308.     old_handler = signal (SIGCHLD, SIG_IGN);
  309. #endif
  310.     if ((stream = popen(command, type)) == NULL)
  311. #ifdef SIGCHLD
  312.     signal (SIGCHLD, old_handler);
  313. #endif
  314.     return (stream);
  315. }
  316.  
  317. mm_pclose (stream)
  318. FILE *stream;
  319. {
  320.     int ret;
  321.  
  322.     ret = pclose (stream);
  323. #ifdef SIGCHLD
  324.     signal (SIGCHLD, old_handler);
  325. #endif
  326.     return (ret);
  327. }
  328.